#include "Widgets.h"
#include "Surface.h"

#include <assert.h>

/** TODO
 * Render all operations onto a seperate surface, then blit that surface at the end.
 * This means that the surface needs only be changed when something about it has 
 * been changed. Also the user can force a reload, but it wouldn't make sense to if nothing has happened.
 */

W_Widget *W_NewW_Widget()
{
	W_Widget *Ret = malloc(sizeof(W_Widget));
	if(Ret == NULL)
		return NULL;
	Ret->Data = NULL;
	return Ret;
}

void W_FreeWidget(W_Widget *Widget)
{
	free(Widget->Data);
	free(Widget);
}

int W_Init()
{
	/*if(TTF_Init() == -1)
		return -1;*/
	if(!TTF_WasInit() && TTF_Init()==-1)
		return -1;

	return 0;
}

inline void DrawLine(int X1, int Y1, int X2, int Y2, SDL_Surface *Surface, W_Colour Colour)
{
	/*Bresenham's line algorithm,
	
	 * adapted to C from:
	 * http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
	 * 
	 * Also modified to support vertical lines
	 */
	if(X1 == X2)
	{
		int Y;
		for(Y = Y1; Y < Y2; ++Y)
		{
			Surface_DrawPixel(Surface, X1, Y, SDL_MapRGB(Surface->format, Colour.R, Colour.G, Colour.B));
		}
		return;
	}
	int Steep = abs(Y2 - Y1) > abs(X2 - X1);
     if(Steep)
     {
         int Temp;
         Temp = X1;
         X1 = X2;
         X2 = Temp;
         Temp = Y1;
         Y1 = Y2;
         Y2 = Temp;
     }
     if(X1 > X2)
     {
         int Temp;
         Temp = X1;
         X1 = X2;
         X2 = Temp;
         Temp = Y1;
         Y1 = Y2;
         Y2 = Temp;
     }
     int DeltaX = X2 - X1;
     int DeltaY = abs(Y2 - Y1);
     int Error = DeltaX / 2;
     int YStep;
     int Y = Y1;
     int X;
     if(Y1 < Y2)
     	YStep = 1;
     else
     	YStep = -1;
     for(X = X1; X < X2; ++X)
     {
         if(Steep)
         	Surface_DrawPixel(Surface, Y, X, SDL_MapRGB(Surface->format, Colour.R, Colour.G, Colour.B));
         else
         	Surface_DrawPixel(Surface, X, Y, SDL_MapRGB(Surface->format, Colour.R, Colour.G, Colour.B));
         Error = Error - DeltaY;
         if(Error < 0)
         {
             Y = Y + YStep;
             Error = Error + DeltaX;
         }
	}
}

inline void DrawRectangleWeighted(int X, int Y, int Width, int Height, int Weight, W_Colour Colour, SDL_Surface *Screen)
{
	int Offset;
	if(Weight == 1) Offset = 0;
	else Offset = Weight/2;
	/*int Xa, Ya;
	for(Ya = Y - Offset; Ya <= Y + Offset; ++Ya)
	{	
		DrawLine(X, Ya, X + Width, Ya, Screen, Colour);
		DrawLine(X, Ya+Height, X+Width, Ya+Height, Screen, Colour);
	}
	for(Xa = X - Offset; Xa <= X + Offset; ++Xa)
	{
		DrawLine(Xa, Y-Offset, Xa, Y+Height+Offset, Screen, Colour);
		DrawLine(Xa+Width, Y-Offset, Xa+Width, Y+Height + Offset, Screen, Colour);
	}*/
	int Pixel = SDL_MapRGB(Screen->format, Colour.R, Colour.G, Colour.B);
	SDL_Rect R;
	R.x = X-Offset;
	R.y = Y;
	R.w = Width + Weight;
	R.h = Weight;
	SDL_FillRect(Screen, &R, Pixel);
	R.y = Y+Height;
	SDL_FillRect(Screen, &R, Pixel);
	R.y = Y;
	R.w = Weight;
	R.h = Height+Offset;
	SDL_FillRect(Screen, &R, Pixel);
	R.x = X+Width - Offset;
	SDL_FillRect(Screen, &R, Pixel);
}


void DrawProgressBar(SDL_Surface *Screen, void *Data)
{
	/* Draw the outside lines */
	//DrawRectangleWeighted(Bar.X, Bar.Y, Bar.Width, Bar.Height, Bar.Weight, Bar.Colour, Screen);
	/* Fill in the progress */
	/*float A = ((float)Bar.Width)/100.0;
	float Length = A * (float)Bar.Progress;

	SDL_Rect R;
	R.x = Bar.X + Bar.Weight/2;
	R.y = Bar.Y + Bar.Weight/2;
	R.w = abs(Length - ((float)Bar.Weight)/2.0);
	R.h = Bar.Height - Bar.Weight/2;
	SDL_FillRect(Screen, &R, SDL_MapRGB(Screen->format, Bar.Colour.R, Bar.Colour.G, Bar.Colour.B));
	*/
	W_ProgressBar *Bar = (W_ProgressBar *)Data;
	DrawRectangleWeighted(Bar->X, Bar->Y, Bar->Width, Bar->Height, Bar->Weight, Bar->Colour, Screen);
	
	float A = ((float)Bar->Width)/100.0;
	float Length = A * (float)Bar->Progress;

	SDL_Rect R;
	R.x = Bar->X + Bar->Weight/2;
	R.y = Bar->Y + Bar->Weight/2;
	R.w = abs(Length - ((float)Bar->Weight)/2.0);
	R.h = Bar->Height - Bar->Weight/2;
	SDL_FillRect(Screen, &R, SDL_MapRGB(Screen->format, Bar->Colour.R, Bar->Colour.G, Bar->Colour.B));
}

W_Widget *W_NewProgressBar(int X, int Y, int Width, int Height, Uint8 Weight, W_Colour Colour)
{
	/*W_ProgressBar Bar = {0.0, Width, Height, X, Y, Colour, Weight};
	W_Widget Ret;
	Ret.Type = Widget_ProgressBar;
	Ret.Bar = Bar;*/
	W_Widget *Ret = W_NewW_Widget();
	if(Ret == NULL)
		return NULL;
	Ret->RenderFunc = DrawProgressBar;
	W_ProgressBar *Bar = malloc(sizeof(W_ProgressBar));
	if(Bar == NULL)
		return NULL;
	Bar->X = X; Bar->Y = Y;
	Bar->Width = Width; Bar->Height = Height;
	Bar->Weight = Weight; Bar->Colour = Colour;
	Bar->Progress = 50;
	Ret->Data = (void *)Bar;
	return Ret;
}

void DrawLabel(SDL_Surface *Surface, void *TData)
{
	/* TODO:
		Change the struct so that quality can also be selected.
	*/
/*printf("Here0\n");
	W_Label *Data = (W_Label *)TData;
	if(Data->Changed)
	{
		printf("Here1\n");
		TTF_Font *Font = TTF_OpenFont(S_GetCString(Data->Font), Data->Size);
		printf("Here2\n");
		SDL_Color C = {Data->Colour.R, Data->Colour.B, Data->Colour.G, 0};
		SDL_Color D = {0, 0, 0, 0};
		//Data->Current = TTF_RenderText_Solid(Data->Font, S_GetCString(Data->Text), C);
		SDL_Surface *Temp = TTF_RenderText_Shaded(Font, S_GetCString(Data->Text), C, D);
		if(Temp == NULL)
			printf("%s\n", TTF_GetError());
		Data->Current = Temp;
		Data->Changed = false;
		printf("Here3\n");
		TTF_CloseFont(Font);
		printf("Here4\n");
	}
	SDL_Rect R;
	R.x = Data->X;
	R.y = Data->Y;
	SDL_BlitSurface(Data->Current, NULL, Surface, &R);*/
}

W_Widget *W_NewLabel(int X, int Y, int Size, S_String *Text, char *FontPath, W_Colour Colour)
{
	/* TODO:
		Check for NULLS!
	*/
	printf("lolwut0\n");
	W_Widget *Ret = malloc(sizeof(Ret));
	Ret->RenderFunc = DrawLabel;
	W_Label *Label = malloc(sizeof(Label));
	Label->X = X;
	Label->Y = Y;
	Label->Size = Size;
	Label->Text = Text;
	Label->Font = FontPath;
	Label->Colour = Colour;
	Label->Changed = true;

	printf("%s\n", Label->Font);
	TTF_Font *Font = TTF_OpenFont(FontPath, Size);
	assert(Font != NULL);
	TTF_CloseFont(Font);
	Ret->Data = Label;
	printf("lolwut1\n");
	return Ret;
}

void W_DrawToSurface(W_Widget *Widget, SDL_Surface *Screen)
{
	Widget->RenderFunc(Screen, Widget->Data);
}
